# -*- coding: utf-8 -*-
from gevent import monkey
monkey.patch_all()

import os
import logging
from datetime import datetime

from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.events import EVENT_JOB_EXECUTED, EVENT_JOB_ERROR, EVENT_JOB_ADDED, EVENT_JOB_SUBMITTED
from apscheduler.executors.pool import ThreadPoolExecutor, ProcessPoolExecutor
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore

from backend.main import create_app, render_template, make_response, current_app, jsonify, request
from backend.ws_server import socketio

from backend import task_worker


app_config = {
    'debug': True
}
app = create_app(app_config)


def scheduler_listener(event, ws_client, scheduler):
    code = getattr(event, 'code')
    job_id = getattr(event, 'job_id')
    jobstore = getattr(event, 'jobstore')
    event_codes = {
        EVENT_JOB_EXECUTED: 'JOB_EXECUTED',
        EVENT_JOB_ERROR: 'JOB_ERROR',
        EVENT_JOB_ADDED: 'JOB_ADDED',
        EVENT_JOB_SUBMITTED: 'JOB_SUBMITTED'
    }
    if code in event_codes:
        event_name = event_codes[code]
        print(event_name)
    # print(job_id)
    job = scheduler.get_job(job_id)
    # print(job)
    if hasattr(event, 'exception') and event.exception:
        error, *_ = event.exception.args
        ws_client.emit('write_task_log', error, path='/ns')
        print(error)

def modify_logger(logger):
    # refer: https://docs.python.org/3.5/library/logging.html#logrecord-attributes
    formatter = logging.Formatter(
        fmt='\n'.join([
            '[%(name)s] %(asctime)s.%(msecs)d',
            '\t%(pathname)s [line: %(lineno)d]',
            '\t%(processName)s[%(process)d] => %(threadName)s[%(thread)d] => %(module)s.%(filename)s:%(funcName)s()',
            '\t%(levelname)s: %(message)s\n'
        ]),
        datefmt='%Y-%m-%d %H:%M:%S'
    )
    # stream_handler = logging.StreamHandler()
    # stream_handler.setFormatter(formatter)
    # logger.addHandler(stream_handler)

    file_handler = logging.FileHandler('task.log', mode='a', encoding='utf-8')
    file_handler.setFormatter(formatter)
    logger.addHandler(file_handler)

    logger.setLevel(logging.INFO)

    return logger

def create_scheduler(ws_client):
    scheduler = BackgroundScheduler()
    _path  = os.path.join(os.path.dirname(__file__), 'jobstore.sqlite')
    if not os.path.exists(_path):
        open(_path, 'ab').close()
        os.utime(_path, None)
    jobstores = {
        'default': SQLAlchemyJobStore(url='sqlite:///{0}'.format(_path))
    }
    executors = {
        'default': ThreadPoolExecutor(20),
        'processpool': ProcessPoolExecutor(5)
    }
    scheduler.configure(jobstores=jobstores, executors=executors)
    scheduler.add_listener(lambda event: scheduler_listener(event, ws_client, scheduler), EVENT_JOB_EXECUTED | EVENT_JOB_ERROR | EVENT_JOB_ADDED | EVENT_JOB_SUBMITTED)
    scheduler._logger = modify_logger(scheduler._logger)

    return scheduler

@app.route('/favicon.ico')
def favicon():
    ico = 'favicon.ico'
    full_ico = os.path.join(app.static_folder, ico)
    if os.path.exists(full_ico):
        return app.send_static_file(ico)
    else:
        return make_response('')

@app.route('/')
def index():
    return '<a href="/sql">==&gt;SQL-WEB</a>'

@app.route('/sql')
def sql_online():
    return render_template('sql.html')

def start_job(sql='', params={}):
    ws_cfg = {
        'host': 'localhost',
        'port': 5000,
        'resource': 'ws',
        'namespace': '/task'
    }
    '''
    real_params = {
        'a': 1,
        'b': 2,
        'ws_cfg': ws_cfg
    }
    '''
    # func = task_worker.test_job_func
    real_params = {
        'sql': sql,
        'params': params,
        'ws_cfg': ws_cfg
    }
    func = task_worker.execute_read
    run_time = datetime.now()
    job = current_app.scheduler.add_job(func, 'date', next_run_time=run_time, kwargs=real_params)
    
    return job.id if not job is None else None

@app.route('/sql-execute', methods=['GET', 'POST'])
def sql_run():
    sql = request.values.get('value', "select '1' from dual")
    params= {}
    job_id = start_job(sql, params)
    return jsonify({
        'job': job_id
    })

@app.route('/send')
def send2all():
    global socketio
    socketio.emit(
        'server_broadcast',
        'broadcast',
        namespace='/ns',
        broadcast=True
    )
    return 'send broadcast ok'
   

if __name__ == '__main__':
    socketio.init_app(app)
    app.socketio = socketio

    scheduler = create_scheduler(socketio)
    app.scheduler = scheduler

    cfg = {
        'host': '0.0.0.0',
        'port': 5000,
        'debug': True
    }
    print('visit by [http://{0}:{1}]'.format(cfg['host'], cfg['port']))
    try:
        scheduler.start()
        socketio.run(app, **cfg, use_reloader=True, log_output=False)
    except (KeyboardInterrupt, SystemExit):
        pass
    finally:
        scheduler.shutdown()
        socketio.stop()